//########################################################################
//## (C) by Edwin Vriethoff under Microsoft Reciprocal License (Ms-RL)  ##
//## See http://www.codeplex.com/SPUserPoll/license for full license    ##
//##                                                                    ##
//## http://edwin.vriethoff.net http://www.codeplex.com/SPUserPoll/     ##
//########################################################################

using System;
using System.Web;
using Microsoft.SharePoint;

namespace SPUserPoll.Data.Components
{
    public class ResponseList
    {
        const string c_ResponseListName = "SPUserPoll responses";
        const string c_ResponseListDesc = "Contains the poll responses";
        const string c_FilterUserResponses = "<Where><Eq><FieldRef Name='Title' /><Value Type='Text'>{0}</Value></Eq></Where>";
        const string c_FilterForResponseCount = "<Where><Eq><FieldRef Name='Voted' /><Value Type='Lookup'>{0}</Value></Eq></Where>";
        const string c_QueryItems = "<Where><IsNotNull><FieldRef Name='Title' /></IsNotNull></Where>";

        /// <summary>
        /// Get the name for the responselist
        /// </summary>
        /// <param name="pollID"></param>
        /// <returns></returns>
        public static string GetResponseListName()
        {
            return c_ResponseListName;
        }

        /// <summary>
        /// Adds a folder for the poll 
        /// </summary>
        /// <param name="pollSite"></param>
        /// <param name="pollTitle"></param>
        /// <param name="pollID"></param>
        /// <returns></returns>
        public SPList RegisterPoll(SPWeb pollSite, string pollTitle, string pollID)
        {
            SPList responseList = GetListForPoll(pollSite);
            try
            {
                responseList.ParentWeb.AllowUnsafeUpdates = true;
                //Add the new poll folder
                SPListItem newFolder = responseList.Items.Add("", SPFileSystemObjectType.Folder, pollTitle);
                FolderUrl = newFolder.Url;
                newFolder.Update();
            }
            finally
            {
                responseList.ParentWeb.AllowUnsafeUpdates = false;
            }
            return responseList;
        }

        public static string FolderUrl;

        /// <summary>
        /// Returns the path for the response folder
        /// </summary>
        /// <param name="pollID"></param>
        /// <returns></returns>
        public static string GetResponseFolderPath(string pollID)
        {
            //Get the folder name
            string pollTitle = AdminList.GetPollTitle(pollID).ToLower();

            //get the list containing the folder
            ResponseList rList = new ResponseList();
            SPList responseList = rList.GetListForPoll(SPContext.Current.Web);
            if (!String.IsNullOrEmpty(pollTitle))
            {
                if (!String.IsNullOrEmpty(FolderUrl))
                    return FolderUrl;
                foreach (SPListItem folder in responseList.Folders)
                {
                    if (folder.Name.ToLower() == pollTitle)
                    {
                        //return the url of the folder
                        FolderUrl = folder.Url;
                        return folder.Url;
                    }
                }
                rList.RegisterPoll(SPContext.Current.Web, pollTitle, pollID);
            }

            
            //return the newly created folder
            return "";
        }

        /// <summary>
        /// Returns the response folder
        /// </summary>
        /// <param name="pollID"></param>
        /// <returns></returns>
        private SPFolder GetResponseFolder(SPWeb web, string pollID)
        {
            //Get the folder name
            string pollTitle = AdminList.GetPollTitle(pollID);

            //get the list containing the folder
            SPList responseList = GetListForPoll(web);
            foreach (SPListItem folder in responseList.Folders)
            {
                if (folder.Name.ToLower() == pollTitle.ToLower())
                {
                    //return the url of the folder
                    return web.GetFolder(folder.UniqueId);
                }
            }

            //the folder has not been found. Create it
            RegisterPoll(web, pollTitle, pollID);
            //return the newly created folder
            return GetResponseFolder(web, pollID);
        }

        /// <summary>
        /// Create a new response list
        /// </summary>
        /// <param name="createAtWeb"></param>
        /// <returns></returns>
        private SPList CreateList(SPWeb createAtWeb)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                //open the required poll list
                using (SPWeb web = new SPSite(createAtWeb.Site.RootWeb.Url).OpenWeb())
                {
                    try
                    {
                        web.AllowUnsafeUpdates = true;

                        string pollResponseList = GetResponseListName();
                        string pollResponseDesc = c_ResponseListDesc;

                        //create the basic list
                        Guid newListGuid = web.Lists.Add(pollResponseList, pollResponseDesc, SPListTemplateType.GenericList);
                        SPList alterList = web.Lists[newListGuid];

                        //rename title column
                        alterList.Fields["Title"].Title = "User";
                        alterList.Fields["Title"].Update();

                        //add lookup column to available answers
                        AnswersList answerList = new AnswersList();
                        SPList lookupList = answerList.GetListForPoll(web);
                        
                        //Add the SPUserPollLookup custom field type with the help of CAML
                        alterList.Fields.AddFieldAsXml("<Field Type=\"SPUserPollLookup\" DisplayName=\"Voted\" Required=\"TRUE\" List=\"{" + lookupList.ID.ToString() + "}\" ShowField=\"Title\" SourceID=\"{" + alterList.ID.ToString() + "}\" StaticName=\"Voted\" Name=\"Voted\" />");
                        
                        //apply updates
                        alterList.Update();

                        //set view
                        SPView defaultView = alterList.DefaultView;
                        defaultView.ViewFields.DeleteAll();
                        defaultView.ViewFields.Add("Type");
                        defaultView.ViewFields.Add("LinkTitle");
                        defaultView.ViewFields.Add("Voted");
                        defaultView.Query = @"<OrderBy><FieldRef Name='ID' /></OrderBy>";
                        defaultView.Update();

                        //Add eventhandler registrations
                        alterList.EventReceivers.Add(SPEventReceiverType.ItemAdded, "SPUserPoll.Business.Components, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b504d4b6c1e1a6e5", "SPUserPoll.Business.Components.AnswerAndResponseEventHandler");
                        alterList.EventReceivers.Add(SPEventReceiverType.ItemUpdated, "SPUserPoll.Business.Components, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b504d4b6c1e1a6e5", "SPUserPoll.Business.Components.AnswerAndResponseEventHandler");
                        alterList.EventReceivers.Add(SPEventReceiverType.ItemDeleting, "SPUserPoll.Business.Components, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b504d4b6c1e1a6e5", "SPUserPoll.Business.Components.AnswerAndResponseEventHandler");
                        alterList.Update();

                    }
                    finally
                    {
                        web.AllowUnsafeUpdates = false;
                    }
                }
            });

            //return the list
            return GetListForPoll(createAtWeb);
        }

        /// <summary>
        /// Register the vote in the response list
        /// </summary>
        /// <param name="pollID"></param>
        /// <param name="userName"></param>
        /// <param name="responseID"></param>
        /// <param name="anonymous"></param>
        public void RegisterVote(string pollID, string userName, int responseID, bool anonymous)
        {
            //Anonymous currenlty not implemented
            //TODO: Implement anonymous

            //Run elevated as the user might not have write rights.
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                //open the required poll list
                string urlForNewSPWebInstance = SPContext.Current.Web.Site.RootWeb.Url;
                HttpContext savedContext = HttpContext.Current;
                HttpContext.Current = null; 
                using (SPWeb web = new SPSite(urlForNewSPWebInstance).OpenWeb())
                {
                    try
                    {
                        web.AllowUnsafeUpdates = true;
                        web.Update();
                        HttpContext.Current = savedContext; //http://hristopavlov.wordpress.com/2008/05/16/what-you-need-to-know-about-allowunsafeupdates/
                        SPList responseList = GetListForPoll(web);
                        SPFolder folder = GetResponseFolder(web, pollID);
                        HttpContext.Current = null;
                        //only register the vote if the folder exists
                        if (folder != null)
                        {
                            SPListItem vote = responseList.Items.Add(folder.ServerRelativeUrl, SPFileSystemObjectType.File);
                            vote["Title"] = userName;
                            vote["Voted"] = responseID;
                            vote.Update();
                            web.Update();
                        }
                    }
                    finally
                    {
                        web.AllowUnsafeUpdates = false;
                        HttpContext.Current = savedContext;
                    }
                }
            });
        }

        /// <summary>
        /// Returns the list for the poll
        /// </summary>
        /// <param name="web"></param>
        /// <param name="pollID"></param>
        /// <returns></returns>
        public SPList GetListForPoll(SPWeb openFromWeb)
        {
            //we recreate the webobject because sharepoint does not see newly created lists in the already openend web
            using (SPWeb web = new SPSite(openFromWeb.Site.RootWeb.Url).OpenWeb())
            {
                try
                {
                    //Check if the folder exist by accessing the list
                    SPList responseList = web.Lists[GetResponseListName()];                 

                    //Return the folder
                    return responseList;
                }
                catch (ArgumentException)
                {
                   
                    //recreate the response list
                    return CreateList(web);
                }
            }
        }

        /// <summary>
        /// Deletes all responses
        /// </summary>
        /// <param name="deleteFromweb"></param>
        /// <param name="pollID"></param>
        public void DeleteAllResponsesForPoll(SPWeb deleteFromweb, string pollID)
        {
            //Requires elevated rights on subsite to access the root site.
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPWeb web = new SPSite(deleteFromweb.Site.RootWeb.Url).OpenWeb())
                {
                    SPList answerList = GetListForPoll(web);

                    //Create the lookup query
                    SPQuery query = new SPQuery();
                    query.Query = c_QueryItems;
                    query.Folder = GetResponseFolder(web, pollID);

                    //Get all items in the folder
                    SPListItemCollection items = answerList.GetItems(query);
                    HttpContext savedContext = HttpContext.Current; //http://hristopavlov.wordpress.com/2008/05/16/what-you-need-to-know-about-allowunsafeupdates/
                    HttpContext.Current = null; 
                    try
                    {
                        web.AllowUnsafeUpdates = true;
                        //Delete the items
                        for (int i = items.Count - 1; i > -1; i--)
                        {
                            items[i].Delete();
                        }
                    }
                    finally
                    {
                        web.Update();
                        web.AllowUnsafeUpdates = false;
                        HttpContext.Current = savedContext;
                    }
                }
            });
        }

        /// <summary>
        /// Returns a count of the response
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        public int GetCountForResponse(string response, string pollID)
        {
            int count = 0;
            //Requires elevated rights on subsite to access the root site.
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPWeb web = new SPSite(SPContext.Current.Web.Site.RootWeb.Url).OpenWeb())
                {
                    SPList responseList = GetListForPoll(web);

                    //Create the lookup query
                    string pollQuery = string.Format(c_FilterForResponseCount, response);
                    SPQuery query = new SPQuery();
                    query.Query = pollQuery;
                    query.Folder = GetResponseFolder(web, pollID);

                    count = responseList.GetItems(query).Count;
                }
            });

            return count;
        }

        /// <summary>
        /// Returns the total number of votes
        /// </summary>
        /// <param name="pollID"></param>
        /// <returns></returns>
        public int GetTotalResponseCount(string pollID)
        {
            int count = 0;
            //Requires elevated rights on subsite to access the root site.
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPWeb web = new SPSite(SPContext.Current.Web.Site.RootWeb.Url).OpenWeb())
                {
                    SPList responseList = GetListForPoll(web);

                    //Create the lookup query
                    string pollQuery = c_QueryItems;
                    SPQuery query = new SPQuery();
                    query.Query = pollQuery;
                    query.Folder = GetResponseFolder(web, pollID);
                    count = responseList.GetItems(query).Count;
                }
            });
            return count;
        }

        /// <summary>
        /// return the item specified by the id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public SPListItem GetItemByID(int id)
        {
            SPList responseList = GetListForPoll(SPContext.Current.Web);
            return responseList.GetItemById(id);
        }

        /// <summary>
        /// Check if the user did vote already on the poll item
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="pollID"></param>
        /// <returns></returns>
        public bool DidTheUserVote(string userName, string pollID)
        {
            bool userVoted = false;

            //Requires elevated rights on subsite to access the root site.
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPWeb web = new SPSite(SPContext.Current.Web.Site.RootWeb.Url).OpenWeb())
                {
                    SPList responseList = GetListForPoll(web);

                    //Create the lookup query
                    string pollQuery = string.Format(c_FilterUserResponses, userName);
                    SPQuery query = new SPQuery();
                    query.Query = pollQuery;
                    query.Folder = GetResponseFolder(web, pollID);

                    //query the list
                    if (responseList.GetItems(query).Count > 0)
                    {
                        userVoted = true;
                    }
                }
            });

            return userVoted;
        }
    }
}